home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** File: Window.c
- ** Written by: Eric Soldan
- **
- ** Copyright © 1990-1993 Apple Computer, Inc.
- ** All rights reserved.
- */
-
- /* You may incorporate this sample code into your applications without
- ** restriction, though the sample code has been provided "AS IS" and the
- ** responsibility for its operation is 100% yours. However, what you are
- ** not permitted to do is to redistribute the source as "DSC Sample Code"
- ** after having made changes. If you're going to re-distribute the source,
- ** we require that you make it clear in the source that the code was
- ** descended from Apple Sample Code, but that you've made changes. */
-
- /* This file contains the code for the document procedure pointers for the main Wannabe
- ** document. Wannabe currently only supports one type of documents, type 'DUMD',
- ** which stands for "DUMb Document". */
-
- /* For more information on this file, please read the read.me file "=How to write your app". */
-
-
-
- /*****************************************************************************/
-
-
-
- #include "App.h" /* Get the application includes/typedefs, etc. */
- #include "App.defs.h" /* Get various application definitions. */
- #include "App.protos.h" /* Get the prototypes for application. */
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef __FONTS__
- #include <Fonts.h>
- #endif
-
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
-
- #ifndef __TOOLUTILS__
- #include <ToolUtils.h>
- #endif
-
- #ifndef __UTILITIES__
- #include "Utilities.h"
- #endif
-
-
-
- /*****************************************************************************/
-
-
-
- Boolean gNoDefaultDocument = false;
- /* Set to true if app should boot with no default document. */
- /* This tells DTS.Lib..framework what you want. */
-
- OSType gAppWindowType = kDocFileType; /* Main document type. */
- long gAppWindowAttr = kwAppWindow; /* Main window attributes. */
-
- short gMinVersion = kMinVersion; /* Minimum document version app can support. */
- short gMaxVersion = kMaxVersion; /* Maximum document version app can support. */
- /* More informing DTS.Lib..framework. */
-
- extern short gPrintPage; /* Non-zero means we are printing. */
- /* DTS.Lib..framework global. */
-
- extern RgnHandle gCursorRgn; /* We handle cursors here, so we need */
- extern CursPtr gCursorPtr; /* to know about these things. */
- /* Above are DTS.Lib..framework globals. */
-
- /* Currently Wannabe doesn't ever change the cursor, so we don't actually need
- ** these referenced here. However, since Wannabe is supposed to be an application
- ** in progress, it is very likely that you will need to reference these as your
- ** project develops. See DTS.StyleChat and DTS.Draw for examples of setting the cursor. */
-
- /* Some cursors are pointer-based, and some cursors are resource-based.
- ** If a cursor is resource-based, it needs to be loaded and made to not move,
- ** and then gCursorPtr can be set to point to it. This makes all cursors
- ** pointer-based. Also, gCursorPtr is used by DTS.Lib..framework to
- ** determine if there is a current cursor. If gCursorPtr is nil, then
- ** there is no current cursor, and the cursor has to be recalculated, no
- ** matter where the mouse is. If gCursorPtr is not nil, then if the
- ** mouse position is within the cursor region gCursorRgn, the cursor is
- ** correct, and no recalculation is necessary. If it is outside this region,
- ** then it is recalculated. What does this all mean? It means that if you
- ** want to guarantee that the cursor is recalculated next time DoWindowCursor()
- ** is called, set gCursorPtr to nil.
- **
- ** If you have a cursor resource, you need to:
- ** 1) Load the resource.
- ** 2) Make a fixed copy of it.
- ** 3) Set the cursor to it.
- ** 4) Set gCursorPtr to point to the fixed copy.
- **
- ** There is a function that does almost all of this, called DoSetResCursor().
- ** It does all but set gCursorPtr to it. (It actually sets gCursorPtr to nil.)
- ** It does return a pointer to the permanent copy, so typically what you will
- ** want to do is the following:
- ** gCursorPtr = DoSetResCursor(theCursorID);
- **
- ** So why set gCursorPtr to nil as the default action? This allows you to
- ** set a temporary cursor, which will be replaced when DoWindowCursor() is
- ** called next, or it allows you to set a cursor that maps to the cursor
- ** region gCursorRgn (by setting gCursorPtr to the return result). */
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Calculate application specific frame area (Called by DoCalcFrameRgn).
- ** You are passed an empty region. You are supposed to add any custom frame
- ** parts that this document uses. Typically there are no frame portions, as
- ** they are accounted for in other ways. The scrollbars and grow icon will
- ** automatically be contributed to the calculation of the frame region.
- ** If you use sidebars, these are also added in automatically. This is only
- ** used if the frame region is more complicated than can automatically be
- ** handled. So, almost always, you will simply leave the region empty. */
-
- #pragma segment TheDoc
- void CalcFrameRgn(FileRecHndl frHndl, WindowPtr window, RgnHandle rgn)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl, window, rgn)
- #endif
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* This is called (by DoContentClick()) when a mouse-down event occurs in the content of
- ** a window. Other applications might want to call FindControl, TEClick, etc., to
- ** further process the click. */
-
- #pragma segment TheDoc
- void ContentClick(WindowPtr window, EventRecord *event, Boolean firstClick)
- {
- #ifndef __MWERKS__
- #pragma unused (firstClick)
- #endif
-
- ControlHandle ctl;
- short action, cnum;
-
- cnum = IsCtlEvent(window, event, &ctl, &action);
- /* That was easy. Scrolling was just handled. Other stuff would be handled
- ** by IsCtlEvent, if we had other stuff to do. We don't have any other
- ** controls in the content besides the document scrollbars. */
-
- return;
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* DoKeyDown() is first called by the application. Then if the key isn't a menu
- ** key, DoKeyDown() calls this code. Here are the rules for this function:
- **
- ** 1) If you handle the key, return(true). This completes the key handling.
- ** 2) If you don't handle the key, you return false. However, there are two
- ** situations for not handling the key:
- ** a) You want someone else to.
- ** b) You want nobody else to look at the key.
- ** This is what the boolean passThrough is for. If you wish the next window
- ** to have a look at the key, set the boolean passThrough to true. passThrough
- ** is already initialized to false, which is the common case, so you only have
- ** to worry about setting it true.
- **
- ** If you have a window that never processes keys and always passes them through,
- ** just set the contentKeyProc to nil. This will indicate to the application
- ** framework that all keys should be passed through this window. DTS.Draw has
- ** such a window. Its palette window doesn't accept keys. They are passed through
- ** to document windows. */
-
- #pragma segment TheDoc
- Boolean ContentKey(WindowPtr window, EventRecord *event, Boolean *passThrough)
- {
- #ifndef __MWERKS__
- #pragma unused (passThrough)
- #endif
-
- short cnum;
-
- cnum = IsCtlEvent(window, event, nil, nil);
- /* See DTS.Draw for an example of what you might do here. */
-
- return(true);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Draw application specific content (Called by DoDrawFrame).
- **
- ** If your application has any custom frame areas, or if it uses sidebars,
- ** this is the function that you would put the frame drawing code. The
- ** document scrollbars and grow icon drawing is handled by DTS.framework.
- ** Just do the sidebar and custom areas here. */
-
- #pragma segment TheDoc
- void DrawFrame(FileRecHndl frHndl, WindowPtr window, Boolean activate)
- {
- MoveTo(0, (*frHndl)->fileState.topSidebar - 1);
- LineTo((*frHndl)->fileState.leftSidebar - 1 - 16384, (*frHndl)->fileState.topSidebar - 1);
- LineTo((*frHndl)->fileState.leftSidebar - 1 - 16384, 16383);
-
- BeginFrame(window);
- DoDrawControls(window, activate);
- EndFrame(window);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Frees up any application-specific memory in the document. This is called by
- ** DoFreeDocument, which is called by DisposeDocument(). The application would
- ** call DisposeDocument(), not DoFreeDocument() or FreeDocument() directly.
- **
- ** The document may have a bunch of handles off the main handle of the document.
- ** This is where they are freed. DisposeDocument calls this prior to releasing
- ** the ram for the main handle of the document, so release everything else
- ** here, or you will have a memory leak.
- **
- ** NOTE: Calling DefaultFreeDocument() frees up all memory used by a
- ** hierarchical document (see TreeObj package). */
-
- #pragma segment TheDoc
- OSErr FreeDocument(FileRecHndl frHndl)
- {
- return(DefaultFreeDocument(frHndl));
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Any additional window disposal tasks can be handled here. */
-
- #pragma segment TheDoc
- OSErr FreeWindow(FileRecHndl frHndl, WindowPtr window)
- {
- #ifndef __MWERKS__
- #pragma unused (window)
- #endif
-
- WindowPtr ww;
- FileRecHndl ff;
-
- if ((*frHndl)->fileState.sfType == kDocFileType) {
- for (ww = nil; (ww = GetNextWindow(ww, 0)) != nil;) {
- ff = (FileRecHndl)GetWRefCon(ww);
- if ((*ff)->fileState.sfType == kViewHierFileType) {
- if ((*frHndl)->d.doc.root == (*ff)->d.doc.root) {
- DisposeOneWindow(ww, kClose);
- ww = nil;
- }
- }
- }
- }
-
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Image the document into the current port.
- **
- ** The only thing tricky about this function is that it needs to key off of
- ** the global variable gPrintPage. gPrintPage is the current page that is
- ** being printed. If gPrintPage is 0, then you are drawing to the window.
- **
- ** For when printing:
- **
- ** If gPrintPage is non-0, that is the page to be printed. If after imaging
- ** the page there are no more pages, you should set gPrintPage to 0. This
- ** indicates to the print loop that the end of the document has been reached.
- ** Even if the user indicated in the job dialog to print more pages, setting
- ** gPrintPage to 0 states that the last page has been printed. This is necessary
- ** because the print loop can't know when printing is done. The imaging procedure
- ** is the logical one to state when everything has been imaged. */
-
- #pragma segment TheDoc
- OSErr ImageDocument(FileRecHndl frHndl)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl)
- #endif
-
- WindowPtr curPort;
-
- GetPort(&curPort);
- if (!gPrintPage) { /* If not printing... */
- DoDrawControls(curPort, false); /* Draw the content controls. */
- }
- gPrintPage = 0;
-
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* This function does the remaining window initialization.
- **
- ** There may be additional content initialization for the window. At this point,
- ** you have a window, but it is currently invisible. If you return noErr, then
- ** the window will be set to the state indicated for that window. Why this function?
- ** You may wish to add controls to the content of the window. You may have a
- ** TextEdit record in the content. All of these sort of things can't be created
- ** until there is a window to contain them. First a document is read in, and then
- ** if the document creation succeeds, a window is created for that document.
- ** At this point we have a document, and we are on our way to having a window.
- ** All that remains is any additional content initialization. Do it, return
- ** noErr, and everybody's happy. If something goes wrong here, return the error,
- ** and the incomplete window will be disposed of. */
-
- #pragma segment TheDoc
- OSErr InitContent(FileRecHndl frHndl, WindowPtr window)
- {
- OSErr err;
-
- err = AddControlSet(window, (*frHndl)->fileState.sfType, kwStandardVis, 0, 0, nil);
- return(err);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* The code below assumes that you are using the hierarchical document package.
- ** If you are, the entire hierarchical document is read in with just these two
- ** calls. If you don't use it, you are on your own. See DTS.StyleChat for an
- ** example of an application that uses the DTS.framework without the hierarchical
- ** document package. */
-
- #pragma segment TheDoc
- OSErr ReadDocument(FileRecHndl frHndl)
- {
- OSErr err;
-
- err = DefaultReadDocument(frHndl);
- if (!err)
- DefaultReadDocumentFixup(frHndl);
-
- return(err);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Resize application specific content (Called by ResizeWindow).
- **
- ** This gets called when a user does a zoom or window resizing operation.
- ** It is possible that things in the content need to be resized in conjunction
- ** with the resizing of the window. */
-
- #pragma segment TheDoc
- void ResizeContent(WindowPtr window, short oldh, short oldv)
- {
- #ifndef __MWERKS__
- #pragma unused (window, oldh, oldv)
- #endif
-
- /* See DTS.StyleChat for a sample usage of this function. */
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Scroll application specific frame (Called by DoScrollFrame).
- **
- ** Some applications may need to scroll the "frame" of the document along
- ** with the document contents. This is common for applications with rulers,
- ** or other similar sidebar items. */
-
- #pragma segment TheDoc
- void ScrollFrame(FileRecHndl frHndl, WindowPtr window, long dh, long dv)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl, window, dh, dv)
- #endif
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* Since the hierarchical document package isn't used by DTS.StyleChat,
- ** this function actually never gets called. */
-
- #pragma segment TheDoc
- void UndoFixup(FileRecHndl frHndl, Point contOrg, Boolean afterUndo)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl, contOrg, afterUndo)
- #endif
-
- /* See DTS.Draw for an example of what you might do here. */
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* This function is where you adjust the cursor to reflect the location in the
- ** document or window. You have the additional input of gCursorRgn to deal
- ** with. The way that the cursor handling works is as follows:
- ** 1) The application calls DoWindowCursor().
- ** 2) DoWindowCursor() works its way through the windows/documents, front to back.
- ** It looks at the document's windowCursorProc and checks to see if the document
- ** has one. If the document doesn't have one, then it assumes that that window
- ** always wants an arrow. If the cursor is over that window, the cursor is set
- ** to an arrow, and we're done. If the cursor isn't over the window, then the next
- ** window is tried. If all documents don't have a windowCursorProc, then the cursor
- ** is set to an arrow (for the non-document area of the screen).
- ** 3) If a document has a windowCursorProc, then the proc is called. The proc's
- ** job is as follows:
- ** a) If the cursor is over a position that is determined by the window, then
- ** the proc removes other areas from gCursorRgn. Note that it should not
- ** simply set the area to what it "thinks" is the correct area. This window
- ** may not be the front-most. Other windows will have already been subtracted
- ** from gCursorRgn. The resultant gCursorRgn is the correct cursor area,
- ** and should be passed to WaitNextEvent calls in the application (already the case
- ** in EventLoop.c). Also, the cursor should be set to the correct cursor, of course.
- ** You should also return true, as the cursor has been determined.
- ** b) If the cursor is not over a position for this window, then you should
- ** return. You will either pass back true or false. If you don't wish
- ** windows behind this window to have a shot at cursor determination, then
- ** return true. This states that the cursor is "determined". It is, in the
- ** sense that no further determination will occur. If you return false, then
- ** other windows get a shot at determining the cursor.
- **
- ** Setting the cursor to the correct cursor isn't as easy as you would expect.
- ** DTS.Lib..framework uses the global gCursorPtr as the reference to the cursor. This is
- ** fine if the cursor is pointer-based, but if the cursor is resource-based, it is a bit
- ** more of a problem. What you will need to do is to call DoSetResCursor() to make the
- ** resource cursor pointer-based. DoSetResCursor() will set gCursorPtr to nil, and it
- ** also returns the pointer to the permanent copy of the cursor resource. Just set gCursorPtr
- ** to the return result of DoSetResCursor(), and you will be set. */
-
- #pragma segment TheDoc
- Boolean WindowCursor(FileRecHndl frHndl, WindowPtr window, Point globalPt)
- {
- #ifndef __MWERKS__
- #pragma unused (frHndl, window, globalPt)
- #endif
-
- /* For examples of applications that have non-arrow cursor regions,
- ** see DTS.StyleChat and DTS.Draw. */
-
- DoSetCursor(&qd.arrow);
- return(true);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* After the DTS.Lib framework disposes of a window, it calls here. This is
- ** to give the application a chance to do any additional tasks related to
- ** a window closing. DTS.StyleChat doesn't have anything else extra to do. */
-
- #pragma segment TheDoc
- void WindowGoneFixup(WindowPtr window)
- {
- #ifndef __MWERKS__
- #pragma unused (window)
- #endif
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- /* The reverse function of ReadDocument. */
-
- #pragma segment TheDoc
- OSErr WriteDocument(FileRecHndl frHndl)
- {
- return(DefaultWriteDocument(frHndl));
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does at open-application time. •• */
-
- #pragma segment TheDoc
- OSErr DoOpenApplication(void)
- {
- return(noErr);
- }
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- #pragma segment TheDoc
- Boolean AdjustMenuItems(WindowPtr window, short menuID)
- {
- Boolean redrawMenuBar;
- MenuHandle menu;
-
- redrawMenuBar = false;
-
- switch (menuID) {
- case mFile:
- redrawMenuBar = DoAdjustFileMenu(window);
- break;
- case mEdit:
- redrawMenuBar = DoAdjustEditMenu(window);
- break;
- default:
- menu = GetMenuHandle(menuID);
- if (menu)
- (*menu)->enableFlags |= 0xFFFFFFFEL;
- break;
- }
-
- return(redrawMenuBar);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* •• You don't call this. DTS.Lib..framework does for appropriate document type(s). •• */
-
- #pragma segment TheDoc
- Boolean DoMenuItem(WindowPtr window, short menuID, short menuItem)
- {
- #ifndef __MWERKS__
- #pragma unused (window)
- #endif
-
- return(DoMenuCommand(menuID, menuItem));
- }
-
-
-
-